package com.heima.media.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.dto.ResponseResult;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.minio.MinIOService;
import com.heima.common.util.SensitiveWordUtil;
import com.heima.media.dto.ArticleDto;
import com.heima.media.dto.ContentDto;
import com.heima.media.dto.ImageDto;
import com.heima.media.entity.WmChannel;
import com.heima.media.entity.WmNews;
import com.heima.media.entity.WmSensitive;
import com.heima.media.entity.WmUser;
import com.heima.media.feign.ArticleClient;
import com.heima.media.service.*;
import org.apache.commons.io.IOUtils;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@Service
public class AuditServiceImpl implements IAuditService {

    @Autowired
    private GreenTextScan textScan;

    @Autowired
    private GreenImageScan imageScan;

    @Autowired
    private IWmNewsService newsService;

    @Autowired
    private MinIOService minIOService;

    @Autowired
    private ArticleClient articleClient;

    @Autowired
    private IWmUserService userService;

    @Autowired
    private IWmChannelService channelService;

    @Autowired
    private IWmSensitiveService sensitiveService;

    /**
     * 文章审核
     *
     * @param wmNews
     */
    @Override
    @Async  // 当前方法是通过线程来执行的
    public void audit(WmNews wmNews) {
        System.out.println(Thread.currentThread().getName() + "开始执行文章审核...");

        if (wmNews.getStatus() == 8 || wmNews.getStatus() == 4) {
            if (wmNews.getPublishTime().getTime() > System.currentTimeMillis()) {
                publishDelayMessage(wmNews);
            } else {
                publishArticle(wmNews);
            }
        }

        // 默认文章状态为 1 提交（待审核）进入自动审核流程
        if (wmNews.getStatus() == 1) {
            // 文章内容中包含文本和图片,提取文本内容和图片
            Map<String, Object> contentMap = getTextAndImageFromContent(wmNews.getContent());
            String text = (String) contentMap.get("text");
            List<String> image = (List<String>) contentMap.get("image");

            // 自管理敏感词审核
            boolean resultWord = checkWord(text, wmNews);
            if (!resultWord) return;
            // 调用阿里云文本审核
            boolean resultText = checkText(text, wmNews);
            if (!resultText) return;
            // 调用阿里云图片审核
            // 图片集合中需要加入封面图片
            List<ImageDto> coverImages = JSON.parseArray(wmNews.getImages(), ImageDto.class);
            for (ImageDto coverImage : coverImages) {
                if (!StringUtils.isEmpty(coverImage.getUrl())) {
                    if (!image.contains(coverImage.getUrl())) {
                        image.add(coverImage.getUrl());
                    }
                }
            }
            boolean resultImage = checkImage(image, wmNews);
            if (!resultImage) return;
            // 调用文章微服务保存文章 发布文章到文章库

            // 判断文章的发布时间是否大于当前系统时间,如果大于当前系统时间,修改状态为 8 审核通过（待发布）
            if (wmNews.getPublishTime().getTime() > System.currentTimeMillis()) {
                publishDelayMessage(wmNews);
            } else {
                publishArticle(wmNews);
            }
        }
    }

    /**
     * 发布文章延迟消息
     *
     * @param wmNews
     */
    private void publishDelayMessage(WmNews wmNews) {
        wmNews.setStatus(8);
        newsService.updateById(wmNews);
        // 发布延迟消息
        RBlockingQueue<String> rQueue = redissonClient.getBlockingQueue("article-publish");
        RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(rQueue);
        // 延迟时间为 文章的发布时间-当前系统时间
        long time = wmNews.getPublishTime().getTime() - System.currentTimeMillis();
        delayedQueue.offer(JSON.toJSONString(wmNews), time, TimeUnit.MILLISECONDS);
    }

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 发送延迟消息
     *
     * @param wmNews
     */
    private void sendDelayMsg(WmNews wmNews) {
        // 创建阻塞队列
        RQueue<String> queue = redissonClient.getBlockingQueue("article-publish");
        // 创建延迟队列
        RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(queue);
        // 使用延迟队列发送延迟消息 参数  消息  延迟时间  时间单位
        // 延迟时间为文章的发布时间-当前系统时间
        long time = wmNews.getPublishTime().getTime() - System.currentTimeMillis();
        delayedQueue.offer(JSON.toJSONString(wmNews), time, TimeUnit.MILLISECONDS);
    }

    /**
     * 自管理敏感词审核
     * @param text
     * @param wmNews
     * @return
     */
    private boolean checkWord(String text, WmNews wmNews) {
        boolean result = false;
        // 判断敏感词库中是否存在数据
        if (SensitiveWordUtil.dictionaryMap.size() == 0) {
            // 不存在的话,查询所有的敏感词,做初始化
            // select sensitives from wm_sensitive
            LambdaQueryWrapper<WmSensitive> query = new LambdaQueryWrapper<>();
            query.select(WmSensitive::getSensitives);
            List<String> words = sensitiveService.listObjs(query, o -> o.toString());
            SensitiveWordUtil.initMap(words);
        }
        // 使用dfa算法来进行匹配
        String content = wmNews.getTitle() + wmNews.getLabels() + text;
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        // 如果map中存在数据,说明敏感词匹配上了
        if (map.size() > 0) {
            // 获取匹配的词
            String reason = String.join(",", map.keySet());
            // 保存失败原因和修改状态
            wmNews.setStatus(2);
            wmNews.setReason("自管理敏感词审核失败,原因是: " + reason);
            newsService.updateById(wmNews);
        }else{
            result = true;
        }
        return result;
    }

    /**
     * 发布文章到文章库
     *
     * @param wmNews
     */
    private void publishArticle(WmNews wmNews) {
        ArticleDto dto = new ArticleDto();
        // 构建文章对象
        BeanUtils.copyProperties(wmNews, dto);
        dto.setId(null);
        // 需要根据user_id找到作者id,查询自媒体用户表
        WmUser wmUser = userService.getById(wmNews.getUserId());
        dto.setAuthorId(wmUser.getApAuthorId());
        dto.setAuthorName(wmUser.getName());
        // 根据channelId查询频道表
        WmChannel wmChannel = channelService.getById(wmNews.getChannelId());
        dto.setChannelName(wmChannel.getName());
        dto.setLayout(wmNews.getType());
        dto.setFlag(0);
        // 需要将图片转成逗号分隔的地址,例如  1.jpg,2.jpg,3.jpg
        List<ImageDto> images = JSON.parseArray(wmNews.getImages(), ImageDto.class);
        List<String> coverImages = new ArrayList<>();
        for (ImageDto image : images) {
            if (!StringUtils.isEmpty(image.getUrl())) {
                coverImages.add(image.getUrl());
            }
        }
        // 将集合转成逗号分隔的字符串
        String join = String.join(",", coverImages);
        dto.setImages(join);
        // 远程调用
        ResponseResult<Long> responseResult = articleClient.saveArticle(dto);
        if (responseResult.getCode().equals(AppHttpCodeEnum.SUCCESS.getCode())) {
            Long articleId = responseResult.getData();
            if (articleId != null) {
                // 将文章id写回到自媒体文章表中
                wmNews.setArticleId(articleId);
                // 将自媒体文章状态改为9 - 已发布
                wmNews.setStatus(9);
                newsService.updateById(wmNews);
            }
        }
    }

    /**
     * 阿里云图片审核
     *
     * @param image
     * @param wmNews
     * @return
     */
    private boolean checkImage(List<String> image, WmNews wmNews) {
        boolean result = false;
        if (image.size() == 0) {
            return true;
        }
        // 如果minio是部署在外网,可以直接使用url地址来检测
        // 如果minio是部署在内网,需要先根据地址从minio下载图片,再进行审核
        List<byte[]> imageList = new ArrayList<>();
        try {
            for (String s : image) {
                // 下载图片
                InputStream inputStream = minIOService.download(s);
                // 将输入流转换成字节数组
                byte[] bytes = IOUtils.toByteArray(inputStream);
                imageList.add(bytes);
            }
            Map map = imageScan.imageScan(imageList);
            // 获取结果
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "pass":
                    result = true;
                    break;
                case "review":
                    // 需要人工审核,修改状态为3
                    wmNews.setStatus(3);
                    newsService.updateById(wmNews);
                    break;
                case "block":
                    // 修改状态为2 ,记录失败原因
                    wmNews.setStatus(2);
                    String label = (String) map.get("label");
                    wmNews.setReason("阿里云图片审核失败,原因是: " + label);
                    newsService.updateById(wmNews);
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 阿里云文本审核
     *
     * @param text
     * @param wmNews
     * @return
     */
    private boolean checkText(String text, WmNews wmNews) {
        boolean result = false;
        // 审核的文本包含 标题+标签+内容中的文字
        String content = wmNews.getTitle() + wmNews.getLabels() + text;
        try {
            Map map = textScan.greenTextScan(content);
            // 获取结果
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "pass":
                    result = true;
                    break;
                case "review":
                    // 需要人工审核,修改状态为3
                    wmNews.setStatus(3);
                    newsService.updateById(wmNews);
                    break;
                case "block":
                    // 修改状态为2 ,记录失败原因
                    wmNews.setStatus(2);
                    String label = (String) map.get("label");
                    wmNews.setReason("阿里云文本审核失败,原因是: " + label);
                    newsService.updateById(wmNews);
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 提取文本内容和图片
     *
     * @param content
     * @return
     */
    private Map<String, Object> getTextAndImageFromContent(String content) {
        Map<String, Object> contentMap = new HashMap<>();
        // 定义文本内容
        StringBuilder stringBuilder = new StringBuilder();
        // 定义图片地址集合
        List<String> images = new ArrayList<>();
        // 解析content
        List<ContentDto> dtos = JSON.parseArray(content, ContentDto.class);
        for (ContentDto dto : dtos) {
            if (dto.getType().equals("text")) {
                // 文本内容,直接拼接在一起
                stringBuilder.append(dto.getValue());
            } else {
                // 图片添加到图片地址集合中
                images.add(dto.getValue());
            }
        }
        String contentText = stringBuilder.toString();
        System.out.println("文本内容: " + contentText);
        contentMap.put("text", contentText);
        contentMap.put("image", images);
        return contentMap;
    }
}
